package logic

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

/*
	.go:代码逻辑
	author : 朝游东海
	clear_old.go : 问题，没有解决当多个文件被争抢的问题。
	5.25 尝试解决
			使用读写锁
			使用读写互斥锁
*/

var wg sync.WaitGroup

//建立长度为100的通道
var pathChan = make(chan *pathStruct,3000)


//写锁
var lock sync.Mutex

//读写互斥锁
var rwLock sync.RWMutex


type pathStruct struct{
	path string
}
var GroupDir string

//NewPathStruct 初始化
func NewPathStruct(path string) *pathStruct{
	return &pathStruct{
		path:path,
	}
}



/*
	func:往通道写入数据
	param :  path 文件路径
	param :  ch 只写通道
*/
func writeValToChan(path string,ch chan <- *pathStruct){
	//lock.Lock()
	rwLock.Lock()
	ch <-  NewPathStruct(path)
	rwLock.Unlock()
	//lock.Unlock()
}


/*
	func:从通道取值
	param :  path 文件路径
	param :  ch 只写通道
*/
func readValToChan( ch <- chan *pathStruct ) string{
	rwLock.RLock()
	p := <- ch
	rwLock.RUnlock()
	return 	p.path
}


/*
	func:根据文件路径删除文件逻辑
	param :  fileOrDirPath 文件路径
	param :  groupDir 超大文件夹group文件路径
	param :  taskNum 开启的线程池数/使用多少个内核线程处理go程序
*/

func ClearLogic(fileOrDirPath,groupDir string,taskNum int){
	//判断是路径是值
	if len(fileOrDirPath) == 0{return}

	startTime := time.Now()

	GroupDir =  strings.TrimSpace(groupDir)

	//设置处理的线程
	setCpuNum(taskNum)

	////消费者，消费大文件
	wg.Add(1)
	go pathChanConsumer( pathChan  )
	//for i:=0; i<3;i++{	}



	//往通道丢需要删除的路径
	wg.Add(1)
	go setValToChan(fileOrDirPath)

	wg.Wait()
	//close(pathChan)

	//for p := range pathChan{
	//	fmt.Println(p.path)
	//}

	fmt.Println( time.Now().Sub(startTime) )

	//2m41.0099618s  - 总体算两三分钟，算快了，之前直接删除文件夹，至少需要半个小时
	//clear over
	//exit status 200

	fmt.Println("clear over")
	os.Exit(200)
}

/*
	func:path通道消费者
	param :  filePath 文件路径
*/
func setCpuNum(taskNum int){
	if taskNum <= 0{
		taskNum = runtime.NumCPU()/2
	}
	runtime.GOMAXPROCS(taskNum) //开启6核处理，避免电脑卡顿
}


/*
	func:path通道消费者
	param :  filePath 文件路径
*/
func pathChanConsumer(ch <- chan *pathStruct){
	defer wg.Done()

	//for p := range pathChan{
	//	wg.Add(1)
	//	//清理文件
	//	go func(path string){
	//		wg.Done()
	//		fmt.Printf("clear ok  %v  \n",path)
	//		//ok,err :=DelAllFileByPath(path);if !ok{
	//		//	fmt.Println("del file fail",path,err)
	//		//}else{
	//		//	fmt.Printf("clear ok  %v  \n",path)
	//		//}
	//	}(p.path)
	//}


	isInitNum := 0
	reduceNum := 0
	for{
		select {
		case p,ok:= <- ch:
			if !ok{
				time.Sleep( time.Millisecond * 500)
				break
			}
			if isInitNum == 0{
				reduceNum = len(pathChan) +1  //加上一句被取出的1个
			}
			isInitNum ++
			//清理文件
			go func(path string,totalNum *int){
				 defer func(){ *totalNum-- }()
				ok,err :=DelAllFileByPath(path);if !ok{
					fmt.Println("del file fail",path,err)
				}else{
					fmt.Printf("clear ok  %v  \n",path)
				}
			}(p.path,&reduceNum)

		default:
			fmt.Println("sleep")
			time.Sleep(time.Millisecond * 500) //当无值从通告取出时，休眠，交出cpu的控制权
		}
		if reduceNum == 0{
			break
		}
	}
}

/*
	func:把值放入通道
	param :  fileOrDirPath 文件路径
*/
func setValToChan(fileOrDirPath string){
	defer wg.Done()
	defer close(pathChan)
	//把字符串切割成切片
	for _,oneFilePath := range strings.Split(fileOrDirPath,","){
		oneFilePath = strings.TrimSpace(oneFilePath)
		if len( oneFilePath ) == 0{
			continue
		}

		//判断文件是否存在  不存在的文件夹，跳过
		if !FileOrDirIsExist(oneFilePath){
			continue
		}

		//wg.Add(1)
		//把值放入通道
		setPathToChan(oneFilePath)
	}

}


/*
	func:把文件路径抛入pathChan通道
	param :  filePath 文件路径
*/
func setPathToChan(filePath string){
	//defer wg.Done()
	if GetFileNameByPath(filePath)== GroupDir {  //大文件单独处理
		setGroupDirPathToChan(filePath)
	}else{
		//把值对于通道
		writeValToChan(filePath,pathChan)
	}
}

/*
	func:把group里面的文件路径抛入通道
	param :  groupDir 文件路径
*/
func setGroupDirPathToChan(groupDir string){
	files := getOneDirAllFileOrDirPath(groupDir);if files != nil{
		for _, file := range files {
			//fmt.Println(path + file.Name())
			writeValToChan(groupDir + file.Name(),pathChan)
		}
	}
}




/*
	func:从通道取值删除 //消费者，消费
	param :  pathChan 文件路径通道
*/
func delFileByPath(pathChan <- chan *pathStruct){
	//defer wg.Done()
	select{
	case v:= <- pathChan:
		//获取文件的名字
		fmt.Println(DelAllFileByPath(v.path))
	default:
		time.Sleep(time.Millisecond * 500)
	}
}



/*
	func:从通道取值
	param :  groupDirFileChan group文件路径通道
	问题：- 未解决
		使用通道，先启用复数go等待通道有值。
		当通道有一个值后，先开启的复数go都会争抢一个数据，导致都删除不了。如果用锁，阻塞，抛弃。
		还会因为go.add()的问题，会导致死锁等问题。
 */

func delGroupDirFile(groupDirFileChan <- chan *pathStruct){
	defer wg.Done()
	select{
	case v:= <- groupDirFileChan:
		//获取文件的名字
		fmt.Println(DelAllFileByPath(v.path))
	default:
		time.Sleep(time.Millisecond * 500)
	}
}


/*
	func:按照group通道里面的文件路径删除文件夹
	param :  path 文件路径
*/
func delGroupDirFileByPath(path string){
	defer wg.Done()
	ret,_ := DelAllFileByPath(path)
	fmt.Println("clear dir " + path + " is " +fmt.Sprintf("%v",ret) )
}